
#include "Triangle.h"
#include "BoundingBox.h"
#include "HitRecord.h"
#include "Point.h"
#include "Ray.h"
#include "Vector.h"
#include <math.h>

Triangle::Triangle(Material* material, const Point& corner1, const Point& corner2, const Point& corner3)
  : Primitive(material), corner1(corner1), corner2(corner2), corner3(corner3)
{
  
}

Triangle::~Triangle()
{
}

void Triangle::getBounds(BoundingBox& bbox) const
{
  bbox.extend(corner1);
  bbox.extend(corner2);
  bbox.extend(corner3);
}

void Triangle::intersect(HitRecord& hit, const RenderContext&, const Ray& ray) const
{
  //algorithm adapted from Thomas Moller and Ben Trumbore
	Vector edge1 = corner2 - corner1;
	Vector edge2 = corner3 - corner1;
	
	//begin calculating determinant - also used to calculate U parameter
	Vector pvec = Cross(ray.direction(), edge2);
	
	//if determinant is near zero, ray lies in plane of triangle
	double determinant = Dot(edge1, pvec);
	
	if(abs(determinant) < EPSILON)
		return;
	double inverse_determinant = 1.0 / determinant;
	
	//calculate distance from vert1 to ray origin
	Vector tvec = ray.origin() - corner1;
	
	//calculate U parameter and test bounds
	double u = Dot(tvec, pvec) * inverse_determinant;
	if (u < 0.0 || u > 1.0)
		return;
	
	//prepare to test V parameter
	Vector qvec = Cross(tvec, edge1);
	
	//calculate V parameter and test bounds
	double v = Dot(ray.direction(), qvec) * inverse_determinant;
	if (v < 0.0 || u + v > 1.0)
		return;
	
	//ray intersects the triangle, calculate t
	double t = Dot(edge2, qvec) * inverse_determinant;
	
	hit.hit(t, this, matl);
	return;
}

void Triangle::normal(Vector& normal, const RenderContext&, const Point& hitpos,
                    const Ray& ray, const HitRecord& hit) const
{
  normal = Cross(corner2 - corner1, corner3 - corner1);
  normal.normalize();
}
